package transformVolOne;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;

/**
 * 
 * @author MacDerson Louis & Candace Schmid
 *
 */
public class ClauseGenerator {

	private ClauseEngine engine;
	private Box[] rect;
	private Random rand;
	private int[] rec;

	public ClauseGenerator(int n, int m){
		engine = new ClauseEngine(n, m);
		rand = new Random();
		engine.fillRectangles();
		rect = engine.getRectangle();
		rec = new int[4];
	}	

	/*clause generator algorithm

		step 1: go through every rectangles corners, and assign each one a random color, by activating
		one of the corner's colors via a true value, and leave the remaining 3 as false.

		step 2: while the grid contains monochromatic colors, go through each rectangle, find the ones
		with monochromatic colorings, and erase and re-color them. otherwise move to next rectangle, and 
		repeat the process of checking for monochromatic colors

		Step 3: when step 2 is complete, write a cnf file containing all the clauses, as well as a discription
		of the file ex. p cnf 4 #clauses.
	 */

	/**
	 * is the given rectangle monochromatic?
	 * @return true if monochromatic, false otherwise
	 */
	public boolean isMono(int[] rec){
		int corn1, corn2, corn3, corn4;

		corn1 = rect[rec[0]].getColor();
		corn2 = rect[rec[1]].getColor();
		corn3 = rect[rec[2]].getColor();
		corn4 = rect[rec[3]].getColor();

		//return true if all corners are the same color.
		return (corn1 == corn2 && corn1 == corn3 && corn1 == corn4 && corn2 == corn3
				&& corn2 == corn4 && corn3 == corn4);
	}//end of isMono()

	/**
	 * assigns a color to every box within the grid
	 */
	public void colorGrid(){		
		int num = 0; 
		for(int i = 0; i < rect.length; i++){
			num = getRandom();
			rect[i].setColor(num, true);
		}
	}//end of colorGrid()

	/**
	 * erases the 4 colors of a given rectangle within the grid, essentially
	 * sets them to false.
	 * @param rec - an integer array containing the index values of 4 boxes
	 * within the grid that make up a rectangle.
	 */
	public void eraseRectColors(int[] rec){
		int num = 0;		

		for(int i = 0; i < rec.length; i++){
			num = rect[rec[i]].getColor();
			rect[rec[i]].setColor(num, false);
		}
	}//end of eraseRectColors()

	/**
	 * colors a given rectangle 
	 * @param rec - array containing the indices of the rectangle within the grid
	 */
	public void paintRectangle(int[] rec){
		for(int i = 0; i < rec.length; i++)
			rect[rec[i]].setColor(getRandom(), true);
	}

	/**
	 * returns a random number from 1 - 4
	 * @return a random number from 1 - 4
	 */
	private int getRandom(){
		return rand.nextInt(4) + 1;
	}//end of getRandom()

	/**
	 * finds and removes any monochromatic rectangles within the grid(if possible)
	 * this may not be possible in all cases.
	 * a monochromatic rectangle is defined as a rectangle whose 4 corners are all the same
	 * color.
	 */
	public void removeMonoRectangles(){
		int num = engine.getNumRect();//how many 2x2 and greater rectangles are in the grid?
		rec = engine.getFirstRectangle();

		while(hasMono(rec, num)){
			eraseRectColors(rec);					
			paintRectangle(rec);
		}
	}//end of removeMonoRectangles

	/**
	 * checks whether the grid has monochromatic rectangles
	 * @return - true if it does, false otherwise
	 */
	public boolean hasMono(int[] rec, int numRect){

		for(int i = 0; i < numRect; i++){
			if(isMono(rec)){//is this rectangle monochromatic?
				return true; //yes this is a monochromatic rectangle
			}
			else{ //no this is not a monochromatic rectangle
				rec = engine.getNextRectangle(rec);//get the next rectangle
				if(rec[3] == 0)//all rectangles have been checked
					break;
			}
		}		
		return false; //grid is not monochromatic
	}

	/**
	 * Generates a cnf text file, to be passed to a satSolver
	 * saves the text file in a folder called cnfFiles, within
	 * project folder.
	 * @param n - row
	 * @param m - column
	 */
	public void generateClauses(int n, int m){
		
		resetEngine();
				
		try{
			writeToFile(n, m);
		}catch(Exception ioEx){
			ioEx.printStackTrace();
		}
	}
	
	/**
	 * write text file containing the clauses, saved in 
	 * @throws IOException 
	 */
	private void writeToFile(int n, int m) throws IOException{
		int num = engine.getNumRect();
		
		String fileName = "newCnfFiles\\cnf" + n + "x" + m + ".txt";
		String cnf = "p cnf 4 " + (num * 4); 
		File clauseFile = new File(fileName);
		int[] clause = null;
		
		FileWriter writer = new FileWriter(clauseFile);
		writer.write(cnf);
		writer.write("\n");
		for(int i = 0; i < num; i++){
			for(int k = 0; k < rec.length; k++){
				clause = rect[rec[k]].getClause();
				for(int j = 0; j < 4; j++){
					writer.write(clause[j] + " ");
				}
				writer.write("0 ");
				writer.write("\n");	
			}
			rec = engine.getNextRectangle(rec);
		}
		writer.close();
	}
	
	/**
	 * resets the variables in clauseEngine in order to perform
	 * the task of generating the clauses that will be passed to the
	 * satSolver.
	 */
	private void resetEngine(){
		engine.resetCurrentN(2); //reset currentN
		engine.resetCurrentM(2); //reset currentM
		engine.setNumberOfIterations(0);
		engine.resetMaxIterations();
		rec = engine.getFirstRectangle();
	}

}//end of class
